package cn.wolfcode.audit.service.impl;

import java.io.InputStream;
import java.util.Collections;
import java.util.List;

import cn.wolfcode.common.utils.DateUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.audit.mapper.AudBpmnInfoMapper;
import cn.wolfcode.audit.domain.AudBpmnInfo;
import cn.wolfcode.audit.service.IAudBpmnInfoService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

/**
 * 流程定义Service业务层处理
 *
 * @author zhangyf
 * @date 2023-04-16
 */
@Service
public class AudBpmnInfoServiceImpl implements IAudBpmnInfoService
{
    @Autowired
    private AudBpmnInfoMapper audBpmnInfoMapper;

    @Autowired
    private RepositoryService repositoryService;


    /**
     * 查询流程定义
     *
     * @param id 流程定义主键
     * @return 流程定义
     */
    @Override
    public AudBpmnInfo selectAudBpmnInfoById(Long id)
    {
        return audBpmnInfoMapper.selectAudBpmnInfoById(id);
    }

    /**
     * 查询流程定义列表
     *
     * @param audBpmnInfo 流程定义
     * @return 流程定义
     */
    @Override
    public List<AudBpmnInfo> selectAudBpmnInfoList(AudBpmnInfo audBpmnInfo)
    {
        return audBpmnInfoMapper.selectAudBpmnInfoList(audBpmnInfo);
    }

    /**
     * 新增流程定义
     *
     * @param audBpmnInfo 流程定义
     * @return 结果
     */
    @Override
    public int insertAudBpmnInfo(AudBpmnInfo audBpmnInfo)
    {
        return audBpmnInfoMapper.insertAudBpmnInfo(audBpmnInfo);
    }

    /**
     * 修改流程定义
     *
     * @param audBpmnInfo 流程定义
     * @return 结果
     */
    @Override
    public int updateAudBpmnInfo(AudBpmnInfo audBpmnInfo)
    {
        return audBpmnInfoMapper.updateAudBpmnInfo(audBpmnInfo);
    }

    /**
     * 批量删除流程定义
     *
     * @param ids 需要删除的流程定义主键
     * @return 结果
     */
    @Override
    public int deleteAudBpmnInfoByIds(Long[] ids)
    {
        return audBpmnInfoMapper.deleteAudBpmnInfoByIds(ids);
    }

    /**
     * 删除流程定义信息
     *
     * @param id 流程定义主键
     * @return 结果
     */
    @Override
    @Transactional
    // 涉及 act_ge_bytearray  act_re_deployment   act_re_procdef   aud_bpmn_info表
    public int deleteAudBpmnInfoById(Long id)
    {
        // 根据 AudBpmnInfo 的 id拿到 流程部署的id值
        AudBpmnInfo audBpmnInfo = audBpmnInfoMapper.selectAudBpmnInfoById(id);
        // 根据key和version查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(audBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(audBpmnInfo.getVersion().intValue())
                .singleResult();

        repositoryService.deleteDeployment(processDefinition.getDeploymentId(),true);
        return audBpmnInfoMapper.deleteAudBpmnInfoById(id);
    }

    @Override
    @Transactional
    public int saveBpmnInfo(AudBpmnInfo audBpmnInfo, InputStream inputStream)
    {
        String bpmnLabel = audBpmnInfo.getBpmnLabel();  // 文件名
        Assert.state(bpmnLabel.endsWith("bpmn"),"文件非法");

        // 调用 activiti API 部署流程定义
        Deployment deployment = repositoryService.createDeployment()
                .addInputStream(bpmnLabel, inputStream)
                .deploy();

        // 根据部署id 查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployment.getId())
                .singleResult();

        // 再往我们设计表 aud bpmn info
        audBpmnInfo.setDeployTime(DateUtils.getNowDate());
        audBpmnInfo.setProcessDefinitionKey(processDefinition.getKey());
        audBpmnInfo.setVersion((long)  processDefinition.getVersion());

        return audBpmnInfoMapper.insertAudBpmnInfo(audBpmnInfo);
    }


    // 前端发送请求 get  /xxx  AudBpmnInfo 的 id  type=xml ,拿到文件内容展示
    // 后端处理请求，肯定会用到响应对象，响应文件内容
    @Override
    public InputStream getInputStream(Long id, String type) {
        // 根据 AudBpmnInfo 的 id拿到 流程部署的id值
        AudBpmnInfo audBpmnInfo = audBpmnInfoMapper.selectAudBpmnInfoById(id);
        // 根据key和version查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(audBpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(audBpmnInfo.getVersion().intValue())
                .singleResult();
        if("xml".equals(type)){
            // 方法1：
            return repositoryService.getProcessModel(processDefinition.getId()); // 流程定义id
            // 方法2：
            // return repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),audBpmnInfo.getBpmnLabel()); // 部署id，文件名
        }
        // 查看流程图
        // 这个对象用来画图的,在内存中画，最终存储到磁盘
        DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
        // 画图，返回 InputStream 对象
        // BpmnModel对象：用来封装我们画的流程图 XML
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        return generator.generateDiagram(bpmnModel,
                // highLightedActivities，highLightedFlows：流程走到哪里就给你高亮。这里不需要高亮，这里没有流程实例，只有流程定义，现在还没有发布审核。在流程实例里高亮。
                Collections.emptyList(),
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体");
    }
}
